package com.zhuqi.service.session.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.zhuqi.properties.NettyProperties;
import com.zhuqi.service.session.Session;
import com.zhuqi.session.user.UserSession;
import com.zhuqi.util.ParamConst;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * @author ZhuQi
 * @ClassName SessionMemoryImpl
 * @Date 2023/1/13 15:54
 * @Version 1.0
 * @Description 本地内存 Session
 */
@Component
@Slf4j
public class SessionMemoryImpl implements Session {

	private final Map<String, Channel> userNameChannelMap = new ConcurrentHashMap<>();
	private final Map<Channel, List<UserSession>> channelUsernameMap = new ConcurrentHashMap<>();
	private final Map<Channel, Map<String, Object>> channelAttributesMap = new ConcurrentHashMap<>();

	@Resource
	private StringRedisTemplate stringRedisTemplate;

	@Resource
	private NettyProperties nettyProperties;

	/**
	 * 绑定会话
	 *
	 * @param channel  那个 channel 要绑定会话
	 * @param userName 会话绑定的用户
	 */
	@Override
	public void bind(Channel channel, String userName) {
		UserSession userSession = new UserSession();
		userSession.setChannel(channel);
		userSession.setName(userName);
		userSession.setLastTime(DateUtil.now());
		userNameChannelMap.put(userName, channel);

		List<UserSession> userSessions = channelUsernameMap.get(channel);
		if (CollectionUtil.isNotEmpty(userSessions)) {
			userSessions.add(userSession);
		} else {
			channelUsernameMap.put(channel, new ArrayList<UserSession>() {{add(userSession);}});
		}

		channelAttributesMap.put(channel, new ConcurrentHashMap<>());

		// 放入 redis
		String key = ParamConst.SESSION_KEY + userName;
		stringRedisTemplate.opsForValue().setIfAbsent(key, userName, nettyProperties.getExpireTime(), TimeUnit.SECONDS);

	}

	/**
	 * 解除会话绑定
	 *
	 * @param channel 那个 Channel 要解绑会话
	 */
	@Override
	public void unbind(Channel channel) {
		List<UserSession> remove = channelUsernameMap.remove(channel);
		if (CollectionUtil.isNotEmpty(remove)) {
			remove.forEach(userSession -> {
				userNameChannelMap.remove(userSession.getName());
				channelAttributesMap.remove(channel);
				String key = ParamConst.SESSION_KEY + userSession.getName();
				stringRedisTemplate.delete(key);
			});
		}
	}


	/**
	 * 根据用户名获取 Channel
	 *
	 * @param userName 用户名
	 * @return channel
	 */
	@Override
	public Channel getChannel(String userName) {
		return userNameChannelMap.get(userName);
	}

	@Override
	public String toString() {
		return userNameChannelMap.toString();
	}


	/**
	 * 用户登出
	 *
	 * @param name 用户名
	 */
	@Override
	public void logOutUser(String name) {
		try {
			userNameChannelMap.remove(name);
			Channel delChannel = null;
			for (Map.Entry<Channel, List<UserSession>> listEntry : channelUsernameMap.entrySet()) {
				List<UserSession> value = listEntry.getValue();
				Iterator<UserSession> iterator = value.iterator();
				while (iterator.hasNext()) {
					UserSession userSession = iterator.next();
					if (name.equalsIgnoreCase(userSession.getName())) {
						iterator.remove();
					}
				}

				if (0 >= value.size()) {
					delChannel = listEntry.getKey();
				}
			}

			Optional.ofNullable(delChannel).ifPresent(channelUsernameMap::remove);
			Optional.ofNullable(delChannel).ifPresent(channelAttributesMap::remove);
		} catch (Exception e) {
			log.info("用户退出出现异常：{}", e.getMessage());
		}
		log.info("用户退出成功：{}", name);
	}

	@Override
	public Map<Channel, List<UserSession>>  getChannelUserSessionMap() {
		return channelUsernameMap;
	}

	@Override
	public void safeDelete() {
		Iterator<Map.Entry<String, Channel>> iterator1 = userNameChannelMap.entrySet().iterator();
		while (iterator1.hasNext()) {
			Map.Entry<String, Channel> next = iterator1.next();
			Channel value = next.getValue();
			if (value == null) {
				iterator1.remove();
			}
			if (!value.isActive()){
				iterator1.remove();
			}
		}

		Iterator<Map.Entry<Channel, List<UserSession>>> iterator2 = channelUsernameMap.entrySet().iterator();
		while (iterator2.hasNext()) {
			Map.Entry<Channel, List<UserSession>> next = iterator2.next();
			Channel value = next.getKey();
			if (value == null) {
				iterator1.remove();
			}
			if (!value.isActive()){
				iterator1.remove();
			}
		}

		Iterator<Map.Entry<Channel, Map<String, Object>>> iterator3 = channelAttributesMap.entrySet().iterator();
		while (iterator3.hasNext()) {
			Map.Entry<Channel, Map<String, Object>> next = iterator3.next();
			Channel value = next.getKey();
			if (value == null) {
				iterator1.remove();
			}
			if (!value.isActive()){
				iterator1.remove();
			}
		}

	}
}
